package com.hex.ds.hdrs.period.job.service;

import cn.afterturn.easypoi.excel.ExcelImportUtil;
import cn.afterturn.easypoi.excel.entity.ImportParams;
import cn.afterturn.easypoi.excel.entity.result.ExcelImportResult;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import com.hex.bigdata.hbda.base.Page;
import com.hex.ds.hdrs.common.annotation.AppCodeVerification;
import com.hex.ds.hdrs.common.constant.Const;
import com.hex.ds.hdrs.common.constant.ErrorCode;
import com.hex.ds.hdrs.common.enums.ExcelImportOperationEnum;
import com.hex.ds.hdrs.common.excel.CycleTaskImportVerifyHandler;
import com.hex.ds.hdrs.common.exception.BizException;
import com.hex.ds.hdrs.common.page.PageData;
import com.hex.ds.hdrs.common.utils.*;
import com.hex.ds.hdrs.label.po.LabelInfoPo;
import com.hex.ds.hdrs.label.service.ILabelInfoService;
import com.hex.ds.hdrs.label.service.ILabelJobService;
import com.hex.ds.hdrs.period.job.converter.IPeriodJobDefConverter;
import com.hex.ds.hdrs.period.job.dao.PeriodJobDefDao;
import com.hex.ds.hdrs.period.job.dto.PeriodJobDefDto;
import com.hex.ds.hdrs.period.job.dto.PeriodJobExportDto;
import com.hex.ds.hdrs.period.job.dto.PeriodJobTaskDto;
import com.hex.ds.hdrs.period.job.po.PeriodJobDef;
import com.hex.ds.hdrs.period.job.vo.PeriodJobAndTaskVo;
import com.hex.ds.hdrs.period.task.converter.IPeriodTaskDefConverter;
import com.hex.ds.hdrs.period.task.dto.PeriodTaskDefDto;
import com.hex.ds.hdrs.period.task.po.PeriodTaskDef;
import com.hex.ds.hdrs.period.task.service.PeriodTaskDefService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 周期作业定义表 服务实现类
 * </p>
 *
 * @author ${author}
 * @since 2020-11-26
 */
@Slf4j
@Service
@RequiredArgsConstructor(onConstructor_ = {@Lazy, @Autowired})
public class PeriodJobDefService {

    private final PeriodJobDefDao periodJobDefDao;

    private final PeriodTaskDefService periodTaskDefService;

    private final ILabelJobService labelJobService;

    private final CycleTaskImportVerifyHandler cycleTaskImportVerifyHandler;

    private final IPeriodJobDefConverter periodJobDefConverter;

    private final IPeriodTaskDefConverter periodTaskDefConverter;

    private final ILabelInfoService labelInfoService;

    @Value("${file.path}")
    private String filePath;

    /*
     * @Method: queryListByPage <br>
     * @Param: [periodJobDefDto, page] <br>
     * @Return: com.hex.ds.hdrs.common.page.PageData <br>
     * @Description：分页查询<br>
     * @Author： wz.li<br>
     * @Date： 2023/5/5 15:02 <br>
     * @Version： V2.0.2<br>
     */
    public PageData queryListByPage(PeriodJobDefDto periodJobDefDto, Page page) {
        PeriodJobDef periodJobDef = periodJobDefConverter.toPeriodJobDefForQuery(periodJobDefDto);
        List<PeriodJobDef> periodJobDefList = periodJobDefDao.queryListByPage(periodJobDef, page);
        for (PeriodJobDef jobDef : periodJobDefList) {
           List<LabelInfoPo> labelInfoPoList = labelInfoService.queryListByJobCode(jobDef.getJobCode());
           jobDef.setLabelName(CollectionUtil.join(labelInfoPoList.stream().map(LabelInfoPo::getLabelName).collect(Collectors.toList()), ","));
        }
        return new PageData(periodJobDefList, page);
    }

    public List<PeriodTaskDef> qryTaskDefVoList(String jobCode) {
        List<PeriodTaskDef> taskDefList = this.periodTaskDefService.getTaskDefsByJobCode(jobCode);

        for (PeriodTaskDef periodTaskDef : taskDefList) {
            // 设置依赖作业名称
            if (StringUtils.isNotBlank(periodTaskDef.getDependJob())) {
                StringBuilder sb = new StringBuilder();
                String[] jobSplit = periodTaskDef.getDependJob().split(",");
                for (int i = 0; i < jobSplit.length; i++) {
                    String depandJobCode = jobSplit[i];
                    PeriodJobDef jobDef = getJobDefByJobCode(depandJobCode);
                    if (null != jobDef) {
                        if (i == jobSplit.length - 1) {
                            sb.append(jobDef.getJobName());
                        } else {
                            sb.append(jobDef.getJobName() + ",");
                        }
                    }
                }
                periodTaskDef.setDependJobName(sb.toString());
            }
            // 设置依赖任务名称
            if (StringUtils.isNotBlank(periodTaskDef.getDependTask())) {
                StringBuilder sb = new StringBuilder();
                String[] taskSplit = periodTaskDef.getDependTask().split(",");
                for (int i = 0; i < taskSplit.length; i++) {
                    String depandTaskCode = taskSplit[i];
                    // 根据任务编码查询
                    PeriodTaskDef taskDef = periodTaskDefService.qryPeriodTaskDef(depandTaskCode);
                    if (null != taskDef) {
                        if (i == taskSplit.length - 1) {
                            sb.append(taskDef.getTaskName());
                        } else {
                            sb.append(taskDef.getTaskName() + ",");
                        }
                    }
                }
                periodTaskDef.setDependTaskName(sb.toString());
            }
        }
        return taskDefList;

    }

    /**
     * 通过jobCode 查询jobDef 信息
     *
     * @param jobCode
     * @return
     */
    public PeriodJobDef getJobDefByJobCode(String jobCode) {
        log.debug("查询JobDef信息【PeriodJobDefService.getJobDefByJobCode】========》jobCode: {}", jobCode);
        Map map = new HashMap();
        map.put("jobCode", jobCode);
        PeriodJobDef periodJobDef = periodJobDefDao.qryJobDef(map);
        if (null != periodJobDef) {
            periodJobDef.setLabelCodeList(labelJobService.queryListByJobCode(periodJobDef.getJobCode()));
        }
        return periodJobDef;
    }

    /**
     * 查询全量作业定义list
     *
     * @return
     */
    public List<PeriodJobDef> qryJobDefList() {
        log.info("查询【PeriodJobDefService.qryJobDefList】");
        Map map = new HashMap();
        return this.periodJobDefDao.qryJobDefList(map);
    }

    /**
     * 通过name与code获取所有作业
     *
     * @param jobDef
     * @param page
     * @return
     */
    public List<PeriodJobDef> getJobList(PeriodJobDef jobDef, Page page) {
        log.debug("分页查询作业信息【PeriodJobDefService.qryJobDefPage】========》jobDef: {}", jobDef);
        Map map = MapUtil.convertObjToMap(jobDef);
        if (StringUtils.isNotBlank(jobDef.getJobCode()) && jobDef.getJobCode().contains(",")) {
            List<String> jobCodeList = Arrays.asList(jobDef.getJobCode().split(","));
            map.put("jobCodeList", jobCodeList);
        }
        map.put("appCode", jobDef.getAppCode());
        List<PeriodJobDef> jobList = null;
        // 1为当前应用 2为其他应用
        if (StringUtils.isBlank(jobDef.getAppName()) || "1".equals(jobDef.getAppName())) {
            jobList = this.periodJobDefDao.qryJobDefPage(map, page);
        } else if ("2".equals(jobDef.getAppName())) {
            jobList = this.periodJobDefDao.qryJobDefPageNotCurrApp(map, page);
        }
        return jobList;

    }

    public List<PeriodJobDef> getJobDefList(String currDate) {
        log.debug("查询周期作业定义数据【PeriodJobDefService.getJobDefList】参数currData: {}", currDate);
        Map map = new HashMap();
        map.put("currDate", currDate);
        return this.periodJobDefDao.getJobDefList(map);
    }

    /*
     * @Method: add <br>
     * @Param: [periodJobDefDto] <br>
     * @Return: com.hex.ds.hdrs.period.job.po.PeriodJobDef <br>
     * @Description：周期作业定义新增<br>
     * @Author： wz.li<br>
     * @Date： 2023/3/22 15:05 <br>
     * @Version： V2.0.2<br>
     */
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public PeriodJobDef add(PeriodJobDefDto periodJobDefDto) {
        PeriodJobDef periodJobDef = periodJobDefConverter.toPeriodJobDefForAdd(periodJobDefDto);
        // 获取app_code，并判断是否为空
        String appCode = periodJobDefDto.getAppCode();
        if (StrUtil.isEmpty(appCode)) {
            log.error("【PeriodJobDefService.add】appCode不存在");
            throw new BizException(ErrorCode.ERROR_910009);
        }
        beforAdd(periodJobDef);
        addPeriodJobDef(periodJobDef);
        addJobLabelInfo(periodJobDefDto);
        log.info("周期作业定义新增,作业编码：{}，业务日期：{}",periodJobDef.getJobCode(),periodJobDef.getBizDate());
        return periodJobDef;
    }

    /*
     * @Method: addJobLabelInfo <br>
     * @Param: [periodJobDefDto] <br>
     * @Return: void <br>
     * @Description：新增作业与标签关联配置<br>
     * @Author： wz.li<br>
     * @Date： 2023/3/29 19:01 <br>
     * @Version： V2.0.2<br>
     */
    private void addJobLabelInfo(PeriodJobDefDto periodJobDefDto) {
        if (CollectionUtil.isNotEmpty(periodJobDefDto.getLabelCodeList())) {
            for (String labelCode : periodJobDefDto.getLabelCodeList()) {
                labelJobService.add(periodJobDefDto.getJobCode(), labelCode);
            }
            log.info("新增作业与标签关联配置,作业编码：{},业务日期：{}",periodJobDefDto.getJobCode(),periodJobDefDto.getBizDate());
        }
    }

    /*
     * @Method: addPeriodJobDef <br>
     * @Param: [periodJobDef] <br>
     * @Return: void <br>
     * @Description：新增周期作业定义<br>
     * @Author： wz.li<br>
     * @Date： 2023/3/22 15:24 <br>
     * @Version： V2.0.2<br>
     */
    private void addPeriodJobDef(PeriodJobDef periodJobDef) {
        log.info("新增周期作业定义,作业编码：{},业务日期：{}",periodJobDef.getJobCode(),periodJobDef.getBizDate());
        int count = periodJobDefDao.insert(periodJobDef);
        if (count != 1) {
            throw new RuntimeException("周期作业定义新增失败，新增返回个数不为1");
        }
    }

    /*
     * @Method: beforAdd <br>
     * @Param: [periodJobDef] <br>
     * @Return: void <br>
     * @Description：新增前业务检查<br>
     * @Author： wz.li<br>
     * @Date： 2023/3/22 15:12 <br>
     * @Version： V2.0.2<br>
     */
    private void beforAdd(PeriodJobDef periodJobDef) {
        log.info("新增前业务检查,作业编码：{},业务日期：{}",periodJobDef.getJobCode(),periodJobDef.getBizDate());
        PeriodJobDef dbPeriodJobDef = queryByJobCode(periodJobDef.getJobCode());
        if (dbPeriodJobDef != null) {
            throw new RuntimeException("作业编码已经存在！");
        }
    }

    /**
     * 查询jobDef 是否存在
     *
     * @param periodJobDef
     * @return 重复返回false, 成功返回true
     */
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public boolean checkAppData(PeriodJobDef periodJobDef) {
        log.debug("查询jobDef 是否存在【PeriodJobDefService.qryJobByJobCode】jobDef========》{}", periodJobDef);
        if (StringUtils.isNotBlank(periodJobDef.getJobName())) {
            return true;
        } else {
            Map<String, String> map = new HashMap<>(16);
            map.put("jobCode", periodJobDef.getJobCode());
            PeriodJobDef dbPeriodJobDef = this.periodJobDefDao.qryJobDef(map);
            if (dbPeriodJobDef != null) {
                return false;
            }
            return true;
        }
    }

    /*
     * @Method: batchRemoveById <br>
     * @Param: [pkIds] <br>
     * @Return: void <br>
     * @Description：根据主键批量删除<br>
     * @Author： wz.li<br>
     * @Date： 2023/3/22 14:23 <br>
     * @Version： V2.0.2<br>
     */
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void batchRemoveById(List<String> pkIds) {
        if (CollectionUtil.isNotEmpty(pkIds)) {
            for (String pkId : pkIds) {
                removeById(pkId);
            }
        }
    }

    /*
     * @Method: removeById <br>
     * @Param: [pkId] <br>
     * @Return: void <br>
     * @Description：根据主键删除<br>
     * @Author： wz.li<br>
     * @Date： 2023/3/22 14:23 <br>
     * @Version： V2.0.2<br>
     */
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void removeById(String pkId) {
        PeriodJobDef periodJobDef = queryById(pkId);
        removePeriodJobById(pkId);
        labelJobService.deleteByJobCode(periodJobDef.getJobCode());

        periodTaskDefService.removeByJobCode(periodJobDef.getJobCode());
    }

    /*
     * @Method: removePeriodJobById <br>
     * @Param: [pkId] <br>
     * @Return: void <br>
     * @Description：根据主键删除周期作业定义<br>
     * @Author： wz.li<br>
     * @Date： 2023/3/27 14:51 <br>
     * @Version： V2.0.2<br>
     */
    private void removePeriodJobById(String pkId) {
        int count = periodJobDefDao.removeById(pkId);
        if (count != 1) {
            throw new RuntimeException("删除周期作业定义失败");
        }
    }

    /*
     * @Method: queryById <br>
     * @Param: [pkId] <br>
     * @Return: com.hex.ds.hdrs.period.job.po.PeriodJobDef <br>
     * @Description：根据主键查询周期作业定义<br>
     * @Author： wz.li<br>
     * @Date： 2023/3/22 14:07 <br>
     * @Version： V2.0.2<br>
     */
    private PeriodJobDef queryById(String pkId) {
        Map queryMap = new HashMap();
        queryMap.put("pkId", pkId);
        return periodJobDefDao.qryJobDef(queryMap);
    }

    /*
     * @Method: queryByJobCode <br>
     * @Param: [jobCode] <br>
     * @Return: com.hex.ds.hdrs.period.job.po.PeriodJobDef <br>
     * @Description：根据作业编码查询周期作业定义<br>
     * @Author： wz.li<br>
     * @Date： 2023/3/22 16:24 <br>
     * @Version： V2.0.2<br>
     */
    private PeriodJobDef queryByJobCode(String jobCode) {
        Map queryMap = new HashMap();
        queryMap.put("jobCode", jobCode);
        return periodJobDefDao.qryJobDef(queryMap);
    }

    /*
     * @Method: modifyById <br>
     * @Param: [periodJobDefDto] <br>
     * @Return: void <br>
     * @Description：更新周期作业定义<br>
     * @Author： wz.li<br>
     * @Date： 2023/3/22 16:38 <br>
     * @Version： V2.0.2<br>
     */
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void modifyById(PeriodJobDefDto periodJobDefDto) {
        modifyById(periodJobDefConverter.toPeriodJobDefForModify(periodJobDefDto));
        labelJobService.update(periodJobDefDto.getJobCode(), periodJobDefDto.getLabelCodeList());
    }

    /*
     * @Method: modifyById <br>
     * @Param: [periodJobDef] <br>
     * @Return: void <br>
     * @Description：更新周期作业定义<br>
     * @Author： wz.li<br>
     * @Date： 2023/3/22 16:40 <br>
     * @Version： V2.0.2<br>
     */
    private void modifyById(PeriodJobDef periodJobDef) {
        log.info("更新周期作业定义，作业编码：{},业务日期：{}",periodJobDef.getJobCode(),periodJobDef.getBizDate());
        int count = periodJobDefDao.update(periodJobDef);
        if (count != 1) {
            throw new RuntimeException("周期作业定义更新失败！");
        }
    }

    /**
     * 根据应用编码获取该应用下的所有周期作业数量
     *
     * @param appCode
     * @return
     */
    public int getPeriodJobDefListByAppCode(String appCode) {
        Map map = new HashMap();
        map.put("appCode", appCode);
        List<PeriodJobDef> jobDefList = this.periodJobDefDao.qryJobDefList(map);
        return ListUtil.isEmpty(jobDefList) ? 0 : jobDefList.size();
    }

    /*
     * @Method: batchUpdateStatus <br>
     * @Param: [periodJobDefDto] <br>
     * @Return: void <br>
     * @Description：批量更新作业状态<br>
     * @Author： wz.li<br>
     * @Date： 2023/3/22 17:45 <br>
     * @Version： V2.0.2<br>
     */
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void batchUpdateStatus(PeriodJobDefDto periodJobDefDto) {
        if (CollectionUtils.isNotEmpty(periodJobDefDto.getSelectionList())) {
            for (String pkId : periodJobDefDto.getSelectionList()) {
                PeriodJobDef periodJobDef = queryById(pkId);
                periodJobDef.setJobStatus(periodJobDefDto.getJobStatus());
                modifyById(periodJobDef);
            }
        }
    }

    /*
     * @Method: batchUpdateJobPeriod <br>
     * @Param: [periodJobDefDto] <br>
     * @Return: void <br>
     * @Description：批量更新作业调度间隔<br>
     * @Author： wz.li<br>
     * @Date： 2023/3/22 17:45 <br>
     * @Version： V2.0.2<br>
     */
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void batchUpdateJobPeriod(PeriodJobDefDto periodJobDefDto) {
        if (CollectionUtils.isNotEmpty(periodJobDefDto.getSelectionList())) {
            for (String pkId : periodJobDefDto.getSelectionList()) {
                PeriodJobDef periodJobDef = queryById(pkId);
                periodJobDef.setJobPeriod(periodJobDefDto.getJobPeriod());
                periodJobDef.setDateExpression(periodJobDefDto.getDateExpression());
                modifyById(periodJobDef);
            }
        }
    }

    public PeriodJobAndTaskVo initJobAndTaskInfo() {
        PeriodJobAndTaskVo periodJobAndTaskVo = new PeriodJobAndTaskVo();
        // 查询所有的作业集合
        List<PeriodJobDef> jobDefs = this.periodJobDefDao.qryJobDefList();
        // 查询所有的任务集合
        List<PeriodTaskDef> taskDefs = this.periodTaskDefService.qryTaskDefList();
        periodJobAndTaskVo.setPeriodJobDefList(jobDefs);
        periodJobAndTaskVo.setPeriodTaskDefList(taskDefs);
        return periodJobAndTaskVo;
    }

    /*
     * @Method: batchUpdateOffsetHour <br>
     * @Param: [periodJobDefDto] <br>
     * @Return: void <br>
     * @Description：批量更新作业偏移小时<br>
     * @Author： wz.li<br>
     * @Date： 2023/3/22 17:38 <br>
     * @Version： V2.0.2<br>
     */
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void batchUpdateOffsetHour(PeriodJobDefDto periodJobDefDto) {
        if (CollectionUtils.isNotEmpty(periodJobDefDto.getSelectionList())) {
            for (String pkId : periodJobDefDto.getSelectionList()) {
                PeriodJobDef periodJobDef = queryById(pkId);
                periodJobDef.setOffsetHour(periodJobDefDto.getOffsetHour());
                modifyById(periodJobDef);
            }
        }
    }

    /*
     * @Method: batchUpdateSortNo <br>
     * @Param: [periodJobDefDto] <br>
     * @Return: void <br>
     * @Description：批量更新周期作业和定义的优先级<br>
     * @Author： wz.li<br>
     * @Date： 2023/3/22 17:38 <br>
     * @Version： V2.0.2<br>
     */
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void batchUpdateSortNo(PeriodJobDefDto periodJobDefDto) {
        if (CollectionUtils.isNotEmpty(periodJobDefDto.getSelectionList())) {
            for (String pkId : periodJobDefDto.getSelectionList()) {
                PeriodJobDef periodJobDef = queryById(pkId);
                periodJobDef.setSortNo(periodJobDefDto.getSortNo());
                modifyById(periodJobDef);
                periodTaskDefService.batchUpdateTaskLevel(periodJobDef.getJobCode(), periodJobDefDto.getSortNo());
            }
        }

    }

    /*
     * @Method: batchUpdateDateRange <br>
     * @Param: [periodJobDefDto] <br>
     * @Return: void <br>
     * @Description：批量更新周期作业定义有效时间<br>
     * @Author： wz.li<br>
     * @Date： 2023/3/22 17:37 <br>
     * @Version： V2.0.2<br>
     */
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void batchUpdateDateRange(PeriodJobDefDto periodJobDefDto) {
        if (CollectionUtils.isNotEmpty(periodJobDefDto.getSelectionList())) {
            for (String pkId : periodJobDefDto.getSelectionList()) {
                PeriodJobDef periodJobDef = queryById(pkId);
                periodJobDef.setIsValidDate(periodJobDefDto.getIsValidDate());
                periodJobDef.setJobStDate(periodJobDefDto.getJobStDate());
                periodJobDef.setJobEndDate(periodJobDefDto.getJobEndDate());
                modifyById(periodJobDef);
            }
        }
    }


    /**
     * 获取当前应用所有依赖作业
     *
     * @return
     */
    @AppCodeVerification(paramObject = LinkedHashMap.class)
    public PageData getDependJobByCurrentApp(Map map) {
        String jobNameOrCode = (String) map.get("jobNameOrCode");
        if (StringUtils.isBlank(jobNameOrCode) || "undefined".equals(jobNameOrCode)) {
            map.remove("jobNameOrCode");
        }
        Page page = new Page();
        page.setPageSize((Integer) map.get("pageSize"));
        page.setPageIndex((Integer) map.get("pageIndex"));
        PageData data = new PageData(this.periodJobDefDao.qryJobDefDependList(map, page), page);
        return data;
    }

    /*
     * @Method: uploadCycleJobDef <br>
     * @Param: [multipartFile, batchTag, appCode] <br>
     * @Return: java.util.Map <br>
     * @Description：EXCEL导入数据<br>
     * @Author： wz.li<br>
     * @Date： 2023/3/22 9:45 <br>
     * @Version： V2.0.2<br>
     */
    public Map importExcel(MultipartFile multipartFile, String batchTag, String appCode) {
        Map resultMap = new HashMap();
        try {
            // 1.检查导入的文件
            checkFile(multipartFile);
            // 2.备份导入的EXCEL文件
            String backUpFilePath = backupUploadFile(multipartFile, batchTag);
            // 3.读取EXCEL文件数据，并做校验
            List<PeriodJobTaskDto> excelData = getExcelData(appCode, backUpFilePath);
            // 4.数据转换
            List<PeriodJobDefDto> periodJobDefDtoList = buildPeriodJobDefDto(excelData, batchTag, appCode);
            // 5.同步数据库数据
            updateDbDataByExcel(periodJobDefDtoList);
            resultMap.put("status", true);
        } catch (Exception e) {
            log.error("导入周期作业/任务定义失败: {}", e.getMessage(), e);
            resultMap.put("status", false);
            resultMap.put("message", e.getMessage());
        }
        return resultMap;
    }

    /*
     * @Method: checkFile <br>
     * @Param: [mf] <br>
     * @Return: void <br>
     * @Description：检查导入的文件<br>
     * @Author： wz.li<br>
     * @Date： 2023/3/21 17:50 <br>
     * @Version： V2.0.2<br>
     */
    private void checkFile(MultipartFile mf) {
        if (mf.isEmpty()) {
            throw new RuntimeException("导入的文件为空文件");
        }
        String type = CheckFileUtil.FileTypeUtils.getFileByFile(MultipartFileUtil.multipartFileToFile(mf));
        if (!Const.FILE_XLS.equals(type) && !Const.FILE_XLSX.equals(type)) {
            throw new RuntimeException("文件类型不符合要求！");
        }
    }

    /**
     * @Method: backupUploadFile <br>
     * @Param: [mf, batchTag, type] <br>
     * @Return: java.lang.String <br>
     * @Description：上传文件保存到服务器<br>
     * @Author： gc.zuo<br>
     * @Date： 2021/7/9 15:12 <br>
     * @Version： V1.0<br>
     */
    private String backupUploadFile(MultipartFile multipartFile, String batchTag) {
        String backUpPath = FilenameUtils.separatorsToSystem(filePath + File.separator + "static/uploadFile/cycleJob");
        com.hex.bigdata.hbda.utils.FileUtil.mkdir(backUpPath);
        String updateFilePath = FilenameUtils.separatorsToSystem(backUpPath + File.separator + batchTag + "_");
        File file = com.hex.bigdata.hbda.utils.FileUtil.upload(multipartFile, updateFilePath);
        log.debug("上传到服务器的EXCEL文件路径: {}", file.getPath());
        return file.getPath();
    }

    /**
     * @Method: checkCycleExcel
     * @Param: [backUpFilePath, batchTag, appCode]
     * @Return: java.util.Map
     * @Description: 检查文件内容
     * @Author: ji.tang
     * @Date: 2023/2/28 17:15
     * @Version: V1.0
     */
    private List<PeriodJobTaskDto> getExcelData(String appCode, String backUpFilePath) {
        ExcelImportResult<PeriodJobTaskDto> convertAfterList = readExcel(appCode, backUpFilePath);
        if (CollectionUtil.isNotEmpty(convertAfterList.getFailList())) {
            StringBuffer sb = new StringBuffer();
            for (PeriodJobTaskDto p : convertAfterList.getFailList()) {
                sb.append("第" + (p.getRowNum() + 1) + "行的错误是：\n" + p.getErrorMsg().replaceAll(",", "\n")).append("\n");
            }
            throw new RuntimeException(sb.toString());
        }
        return convertAfterList.getList();
    }

    /*
     * @Method: readExcel <br>
     * @Param: [backUpFilePath] <br>
     * @Return: cn.afterturn.easypoi.excel.entity.result.ExcelImportResult<com.hex.ds.hdrs.period.job.dto.PeriodJobTaskDto> <br>
     * @Description：读取EXCEL中的数据<br>
     * @Author： wz.li<br>
     * @Date： 2023/3/21 18:11 <br>
     * @Version： V2.0.2<br>
     */
    private ExcelImportResult<PeriodJobTaskDto> readExcel(String appCode, String backUpFilePath) {
        ImportParams importParams = new ImportParams();
        importParams.setNeedVerify(true);//开启校验
        importParams.setVerifyHandler(cycleTaskImportVerifyHandler); //自定义校验
        cycleTaskImportVerifyHandler.setAppCode(appCode);
        cycleTaskImportVerifyHandler.getThreadLocal().remove();
        return ExcelImportUtil.importExcelMore(new File(backUpFilePath), PeriodJobTaskDto.class, importParams);
    }

    /**
     * @Method: updateDbMemByExcelUpload
     * @Param: [checkMap, status, message]
     * @Return: void
     * @Description: 同步数据库数据
     * @Author: ji.tang
     * @Date: 2023/2/28 17:11
     * @Version: V1.0
     */
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void updateDbDataByExcel(List<PeriodJobDefDto> periodJobDefDtoList) {
        if (CollectionUtil.isNotEmpty(periodJobDefDtoList)) {
            for (PeriodJobDefDto periodJobDefDto : periodJobDefDtoList) {
                updatePeriodTaskDefByExcel(periodJobDefDto);
                updatePeriodJobDefByExcel(periodJobDefDto);
            }
        }
    }

    /*
     * @Method: updatePeriodTaskDefByExcel <br>
     * @Param: [periodJobDefDto] <br>
     * @Return: void <br>
     * @Description：更新周期任务定义<br>
     * @Author： wz.li<br>
     * @Date： 2023/3/27 15:09 <br>
     * @Version： V2.0.2<br>
     */
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void updatePeriodTaskDefByExcel(PeriodJobDefDto periodJobDefDto) {
        for (PeriodTaskDefDto periodTaskDefDto : periodJobDefDto.getPeriodTaskDefDtoList()) {
            log.info("import excel data index: {}", periodJobDefDto.getPeriodTaskDefDtoList().indexOf(periodTaskDefDto));
            if (ExcelImportOperationEnum.A.getName().equals(periodTaskDefDto.getOperation())) {
                periodTaskDefService.add(periodTaskDefConverter.toPeriodTaskDefForAdd(periodTaskDefDto));
            } else if (ExcelImportOperationEnum.U.getName().equals(periodTaskDefDto.getOperation())) {
                periodTaskDefService.modifyByCode(periodTaskDefConverter.toPeriodTaskDefForModify(periodTaskDefDto));
            } else if (ExcelImportOperationEnum.D.getName().equals(periodTaskDefDto.getOperation())) {
                periodTaskDefService.removeByTaskCode(periodTaskDefDto.getTaskCode());
            }
        }
    }

    /*
     * @Method: updatePeriodJobDefByExcel <br>
     * @Param: [periodJobDefDto] <br>
     * @Return: void <br>
     * @Description：更新周期作业定义<br>
     * @Author： wz.li<br>
     * @Date： 2023/3/27 15:08 <br>
     * @Version： V2.0.2<br>
     */
    private void updatePeriodJobDefByExcel(PeriodJobDefDto periodJobDefDto) {
        PeriodJobDef dbPeriodJobDef = queryByJobCode(periodJobDefDto.getJobCode());
        List<PeriodTaskDef> periodTaskDefList = periodTaskDefService.getTaskDefsByJobCode(periodJobDefDto.getJobCode());
        if (dbPeriodJobDef != null && CollectionUtil.isEmpty(periodTaskDefList)) {
            removePeriodJobById(dbPeriodJobDef.getPkId());
            labelJobService.deleteByJobCode(dbPeriodJobDef.getJobCode());
        } else if (dbPeriodJobDef == null && CollectionUtil.isNotEmpty(periodTaskDefList)) {
            addPeriodJobDef(periodJobDefConverter.toPeriodJobDefForAdd(periodJobDefDto));
            labelJobService.update(periodJobDefDto.getJobCode(), periodJobDefDto.getLabelJobCodeList());
        } else {
            periodJobDefDto.setPkId(dbPeriodJobDef.getPkId());
            modifyById(periodJobDefDto);
            labelJobService.update(periodJobDefDto.getJobCode(), periodJobDefDto.getLabelJobCodeList());
        }
    }

    /*
     * @Method: buildPeriodJobDefDto <br>
     * @Param: [excelData, batchTag, appCode] <br>
     * @Return: java.util.List<com.hex.ds.hdrs.period.job.dto.PeriodJobDefDto> <br>
     * @Description：构建周期作业/任务定义对象<br>
     * @Author： wz.li<br>
     * @Date： 2023/3/22 13:42 <br>
     * @Version： V2.0.2<br>
     */
    private List<PeriodJobDefDto> buildPeriodJobDefDto(List<PeriodJobTaskDto> excelData, String batchTag, String appCode) {
        Map<String, PeriodJobDefDto> periodJobDefDtoMap = new HashMap<>();
        StringBuilder sb = new StringBuilder();
        if (CollectionUtil.isNotEmpty(excelData)) {
            for (PeriodJobTaskDto periodJobTaskDto : excelData) {
                PeriodJobDefDto periodJobDefDto = periodJobDefDtoMap.get(periodJobTaskDto.getJobCode());
                if (sb.length() > 0) {
                    sb.append(", ");
                }
                sb.append(periodJobTaskDto.getJobCode());
                if (periodJobDefDto == null) {
                    periodJobDefDto = periodJobDefConverter.toPeriodJobDefDto(periodJobTaskDto, batchTag, appCode);
                    periodJobDefDtoMap.put(periodJobTaskDto.getJobCode(), periodJobDefDto);
                }
                periodJobDefDto.getPeriodTaskDefDtoList().add(periodTaskDefConverter.toPeriodTaskDefDto(periodJobTaskDto, appCode));
            }
            log.info("构建周期作业/任务定义对象:{}", sb);
        }
        return new ArrayList<>(periodJobDefDtoMap.values());
    }

    /*
     * @Method: exportExcel <br>
     * @Param: [periodJobDef] <br>
     * @Return: java.lang.String <br>
     * @Description：导出<br>
     * @Author： wz.li<br>
     * @Date： 2023/3/27 19:33 <br>
     * @Version： V2.0.2<br>
     */
    public String exportExcel(PeriodJobDef periodJobDef) {
        List<PeriodJobExportDto> exportDtoList = getExportData(periodJobDef);
        String backUpPath = createSavePath();
        String templateFilePath = "static/period_job_and_task_import_template.xlsx";
        String saveFilePath = backUpPath + File.separator + "周期作业-任务定义数据.xlsx";
        ExcelDownUtil.generatedExcel(exportDtoList, templateFilePath, saveFilePath);
        return saveFilePath;
    }

    /*
     * @Method: createSavePath <br>
     * @Param: [] <br>
     * @Return: java.lang.String <br>
     * @Description：创建导出备份目录<br>
     * @Author： wz.li<br>
     * @Date： 2023/3/27 19:33 <br>
     * @Version： V2.0.2<br>
     */
    private String createSavePath() {
        String savePath = filePath + File.separator + "static/downExcel/cycleJob" + File.separator + cn.hutool.core.date.DateUtil.today() + File.separator + DateUtil.current(false);
        FileUtil.mkdir(savePath);
        return FilenameUtils.separatorsToSystem(savePath);
    }

    /*
     * @Method: getExportData <br>
     * @Param: [periodJobDef] <br>
     * @Return: java.util.List<com.hex.ds.hdrs.period.job.dto.PeriodJobExportDto> <br>
     * @Description：获取导出数据<br>
     * @Author： wz.li<br>
     * @Date： 2023/3/27 19:34 <br>
     * @Version： V2.0.2<br>
     */
    private List<PeriodJobExportDto> getExportData(PeriodJobDef periodJobDef) {
        List<PeriodJobExportDto> exportDtoList = periodJobDefDao.qryJobDefAndTaskDefList(periodJobDef);
        int index = 1;
        for (PeriodJobExportDto periodJobExportDto : exportDtoList) {
            List<String> labelCodeList = labelJobService.queryListByJobCode(periodJobExportDto.getJobCode());
            periodJobExportDto.setIndex(index++).setLabelName(StrUtil.join(",", labelCodeList));
        }
        return exportDtoList;
    }

}
